package com.test.event.config;

import com.test.event.listener.EventListener;
import com.test.event.service.impl.NameEvent;
import org.springframework.stereotype.Component;

import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class EventDispatcher implements Closeable {

    private ExecutorService executor;

    private final ConcurrentMap<String, EventListener> observerMap = new ConcurrentHashMap<>();

    private volatile boolean closed = false;

    private AtomicInteger count = new AtomicInteger(1);

    public EventDispatcher() {
        this.executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(10), new ThreadPoolExecutor.AbortPolicy());

        this.executor.execute(() -> {
            while (!closed) {
                if (!observerMap.isEmpty()) {
                    observerMap.entrySet()
                            .forEach(entry -> {
                                if (count.getAndIncrement() <= 10) {
                                    entry.getValue().onEvent(NameEvent.builder()
                                            .name(entry.getKey())
                                            .build());
                                }
                            });
                }
            }
        });
    }

    @Override
    public void close() throws IOException {
        closed = true;
    }

    public void addListener(String name, EventListener listener) {
        observerMap.putIfAbsent(name, listener);
    }

    public void removeListener(String name) {
        observerMap.remove(name);
    }
}
